(function()
{
	var BEFOREREQUEST = "beforerequest", 
		REQUESTCOMPLETE = "requestcomplete", 
		REQUESTEXCEPTION = "requestexception", 
		UNDEFINED = undefined, 
		LOAD = 'load', 
		POST = 'POST', 
		GET = 'GET', 
		WINDOW = window;

	Ext.data.Connection = function( config )
	{
		Ext.apply(this, config);
		this.addEvents(BEFOREREQUEST, REQUESTCOMPLETE, REQUESTEXCEPTION);
		Ext.data.Connection.superclass.constructor.call(this);
	};

	Ext.extend(Ext.data.Connection, Ext.util.Observable,
	{
		timeout: 30000,
		autoAbort: false,
		disableCaching: true,
		disableCachingParam: '_dc',

		request: function( o )
		{
			var me = this;
			// 触发beforerequest事件，如果返回false，则立马停止
			if( me.fireEvent(BEFOREREQUEST, me, o) !== false)
			{
				if( o.el ) // 哦哦，这里是个指示器，用来显示最后的responseText，api文档上为啥木有，莫非是个隐藏功能?!!!
				{
					if( !Ext.isEmpty(o.indicatorText) )
					{
						me.indicatorText = '<div class="loading-indicator">' + o.indicatorText + "</div>";
					}
					if( me.indicatorText )
					{
						Ext.getDom(o.el).innerHTML = me.indicatorText;
					}
					o.success = (Ext.isFunction(o.success) ? o.success : function()
					{
					}).createInterceptor(function( response )
					{
						Ext.getDom(o.el).innerHTML = response.responseText;
					});
				}

				var p = o.params, url = o.url || me.url, method, cb =
				{
					success: me.handleResponse, //包装之
					failure: me.handleFailure,
					scope: me,
					argument:
					{
						options: o
					},
					timeout: Ext.num(o.timeout, me.timeout)
				}, form, serForm;

				if( Ext.isFunction(p) )
				{
					p = p.call(o.scope || WINDOW, o);
				}

				p = Ext.urlEncode(me.extraParams, Ext.isObject(p) ? Ext.urlEncode(p) : p);

				if( Ext.isFunction(url) )
				{
					url = url.call(o.scope || WINDOW, o);
				}

				if( (form = Ext.getDom(o.form)) )
				{
					url = url || form.action;
					if( o.isUpload || (/multipart\/form-data/i.test(form.getAttribute("enctype"))) )
					{
						return me.doFormUpload.call(me, o, p, url);
					}
					serForm = Ext.lib.Ajax.serializeForm(form);
					p = p ? (p + '&' + serForm) : serForm;
				}

				method = o.method || me.method || ((p || o.xmlData || o.jsonData) ? POST : GET);

				// disableCaching 为禁用缓存，默认为true，表示禁用 _dc=Math.random().getTime()
				if( method === GET && (me.disableCaching && o.disableCaching !== false) || o.disableCaching === true )
				{
					var dcp = o.disableCachingParam || me.disableCachingParam;
					url = Ext.urlAppend(url, dcp + '=' + (new Date().getTime())); // 杀缓存！
				}

				o.headers = Ext.applyIf(o.headers || {}, me.defaultHeaders || {});

				if( o.autoAbort === true || me.autoAbort )
				{
					me.abort();
				}

				if( (method == GET || o.xmlData || o.jsonData) && p )
				{
					url = Ext.urlAppend(url, p);
					p = '';
				}
				return (me.transId = Ext.lib.Ajax.request(method, url, cb, p, o));
			}
			else
			{
				//如果在beforereqest中返回了false，那么就直接执行callback了
				//这里根本就执行不到，莫非，我要new Ext.data.Connection么，来试试
				//经过实验，是可以的，我们可以这样，就不发ajax请求了
				
				/*var ajax = new Ext.data.Connection(
				{
					autoAbort: false,
					listeners:
					{
						'beforerequest': function()
						{
							return false;
						}
					}
				});
				
				ajax.request(
				{
					method: 'GET',
					url: 'data.json',
					callback: function( options, success, response )
					{
						console.log(options, success, response);
					},
					scope:
					{
						name: 'abc'
					},
					timeout: 2000,
					el: 'box'
				});*/

				
				return o.callback ? o.callback.apply(o.scope,
				[
				    o, UNDEFINED, UNDEFINED
				]) : null;
			}
		},

		//判断是否正在请求
		isLoading: function( transId )
		{
			return transId ? Ext.lib.Ajax.isCallInProgress(transId) : !!this.transId;
		},

		
		//停止请求
		abort: function( transId )
		{
			if( transId || this.isLoading() )
			{
				Ext.lib.Ajax.abort(transId || this.transId);
			}
		},

		// private
		//如果配置callback:function () {}那么，response.argument就是callback的argument
		//这个response，是从Ext.lib.Ajax里传过来的，
		/*responseObject 
    	{
            tId : o.tId,
            // Normalize the status and statusText when IE returns 1223, see the above link.
            status : isBrokenStatus ? 204 : conn.status,
            statusText : isBrokenStatus ? 'No Content' : conn.statusText,
            getResponseHeader : function(header){return headerObj[header.toLowerCase()];},
            getAllResponseHeaders : function(){return headerStr;},
            responseText : conn.responseText,
            responseXML : conn.responseXML,
            argument : {options:o}
    	}*/
		//这个options里存的，就是Ext.Ajax.request({callback:function () {},scope:this,method:'get',url:'xxxx.action'});
		//options是兜了一大圈，最后又传过来
		handleResponse: function( response )
		{
			this.transId = false;
			var options = response.argument.options;
			
			response.argument = options ? options.argument : null;
			
			//触发requestcomplete!
			this.fireEvent(REQUESTCOMPLETE, this, response, options);
			
			//调用之
			if( options.success )
			{
				options.success.call(options.scope, response, options);
			}
			if( options.callback )
			{
				options.callback.call(options.scope, options, true, response);
			}
		},

		// 失败的包装函数
		handleFailure: function( response, e )
		{
			this.transId = false;
			var options = response.argument.options;
			response.argument = options ? options.argument : null;
			this.fireEvent(REQUESTEXCEPTION, this, response, options, e);
			if( options.failure )
			{
				options.failure.call(options.scope, response, options);
			}
			if( options.callback )
			{
				options.callback.call(options.scope, options, false, response);
			}
		},

		// private
		doFormUpload: function( o, ps, url )
		{
			var id = Ext.id(), doc = document, frame = doc.createElement('iframe'), form = Ext.getDom(o.form), hiddens = [], hd, encoding = 'multipart/form-data', buf =
			{
				target: form.target,
				method: form.method,
				encoding: form.encoding,
				enctype: form.enctype,
				action: form.action
			};

			/*
			 * Originally this behaviour was modified for Opera 10 to apply the secure URL after the frame had been added to the document. It seems this has since
			 * been corrected in Opera so the behaviour has been reverted, the URL will be set before being added.
			 */
			Ext.fly(frame).set(
			{
				id: id,
				name: id,
				cls: 'x-hidden',
				src: Ext.SSL_SECURE_URL
			});

			doc.body.appendChild(frame);

			// This is required so that IE doesn't pop the response up in a new window.
			if( Ext.isIE )
			{
				document.frames[id].name = id;
			}

			Ext.fly(form).set(
			{
				target: id,
				method: POST,
				enctype: encoding,
				encoding: encoding,
				action: url || buf.action
			});

			// add dynamic params
			Ext.iterate(Ext.urlDecode(ps, false), function( k, v )
			{
				hd = doc.createElement('input');
				Ext.fly(hd).set(
				{
					type: 'hidden',
					value: v,
					name: k
				});
				form.appendChild(hd);
				hiddens.push(hd);
			});

			function cb()
			{
				var me = this,
				// bogus response object
				r =
				{
					responseText: '',
					responseXML: null,
					argument: o.argument
				}, doc, firstChild;

				try
				{
					doc = frame.contentWindow.document || frame.contentDocument || WINDOW.frames[id].document;
					if( doc )
					{
						if( doc.body )
						{
							if( /textarea/i.test((firstChild = doc.body.firstChild || {}).tagName) )
							{ // json response wrapped in textarea
								r.responseText = firstChild.value;
							}
							else
							{
								r.responseText = doc.body.innerHTML;
							}
						}
						// in IE the document may still have a body even if returns XML.
						r.responseXML = doc.XMLDocument || doc;
					}
				}
				catch (e)
				{
				}

				Ext.EventManager.removeListener(frame, LOAD, cb, me);

				me.fireEvent(REQUESTCOMPLETE, me, r, o);

				function runCallback( fn, scope, args )
				{
					if( Ext.isFunction(fn) )
					{
						fn.apply(scope, args);
					}
				}

				runCallback(o.success, o.scope,
				[
				    r, o
				]);
				runCallback(o.callback, o.scope,
				[
				    o, true, r
				]);

				if( !me.debugUploads )
				{
					setTimeout(function()
					{
						Ext.removeNode(frame);
					}, 100);
				}
			}

			Ext.EventManager.on(frame, LOAD, cb, this);
			form.submit();

			Ext.fly(form).set(buf);
			Ext.each(hiddens, function( h )
			{
				Ext.removeNode(h);
			});
		}
	});
})();

Ext.Ajax = new Ext.data.Connection(
{
	autoAbort: false,
	serializeForm: function( form )
	{
		return Ext.lib.Ajax.serializeForm(form);
	}
});
